fix(install): ship the frozen 8-member payload so older promoters accept genie update - #2891
Conversation
…ept genie update `genie update` is executed by the previously installed binary, whose `INSTALL_PAYLOAD_MEMBERS` copy validates the downloaded tarball as an exact set. 5.260901.1 dropped `.agents/` and `.claude-plugin/` (wish skills-everywhere-b, G3/G4) and moved the allowlist with it — correct for fresh `install.sh` installs, but every 5.260831.x host running `genie update` failed with "staged install does not match the exact installer member allowlist". - build-binary.sh stages both directories again, empty; nothing reads them. - INSTALL_PAYLOAD_MEMBERS / EXPECTED_MEMBER_KINDS are back to the eight members, documented as a frozen cross-release contract, with INSTALL_PAYLOAD_COMPAT_MEMBERS naming the two content-free entries. - Fixtures mirror the real tarball; new tests pin the frozen set, prove empty compat dirs are admitted and published, and guard the build script. Proof (installed 5.260831.6 promoter, isolated HOME, `__install-promote`): the published 5.260901.1 layout fails with the exact production error; the tarball built from this commit commits and publishes all 8 members. Hosts that installed 5.260901.1 fresh carry the six-member allowlist and need one `install.sh` reinstall; noted in CHANGELOG. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVnr6rZxYhbC8rU62A1U2i
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6ff3d8572e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # so the tarball's top-level set is frozen: dropping these directories broke | ||
| # `genie update` on every 5.260831.x host (5.260901.1). They ship empty and | ||
| # nothing reads them; only remove them together with a shape-tolerant promoter. | ||
| mkdir -p "${STAGE}/.agents" "${STAGE}/.claude-plugin" |
There was a problem hiding this comment.
Force safe modes on compatibility directories
When a release is built under a common group-writable umask such as 002, this mkdir -p records both new directories as 0775. install.sh extracts the archive with tar -xzpf (whose -p preserves archived permissions), and assertSafeOwnedNode rejects any payload member with mode bits 0022, so the resulting tarball cannot be installed or promoted. Create these directories with a normalized 0755 mode (and verify that mode in the extracted archive) rather than inheriting the build environment's umask.
AGENTS.md reference: AGENTS.md:L55-L57
Useful? React with 👍 / 👎.
Problem
genie updatefrom any 5.260831.x host to 5.260901.1 fails:genie updateruns on the previously installed binary. Its promoter (verifyPayloadLayout,src/lib/install-promotion.ts) validates the downloaded tarball's top-level entries against its baked-inINSTALL_PAYLOAD_MEMBERSas an exact set. Wishskills-everywhere-b(G36b3ecde26, G4e250b9463) dropped.agents/and.claude-plugin/from the tarball and moved the allowlist with it — proven only for freshinstall.shinstalls, where the new binary promotes itself. The old-binary→new-payload hop was never exercised..agents .claude-plugin LICENSE VERSION genie plugins skills templatesLICENSE VERSION genie plugins skills templatesFix
scripts/build-binary.shstages.agents/and.claude-plugin/again — empty, nothing reads them.INSTALL_PAYLOAD_MEMBERS/EXPECTED_MEMBER_KINDSback to the eight members, documented as a frozen cross-release contract;INSTALL_PAYLOAD_COMPAT_MEMBERSnames the two content-free entries.release-docs.test.ts).CHANGELOG.mdentry.Proof
Ran the installed 5.260831.6 promoter (
genie __install-promote, isolatedHOME/GENIE_HOME, borrowed lease asinstall.shdoes) against both layouts:genie-5.260901.1-linux-x64-glibc.tar.gz→InstallPromotionError: staged install does not match the exact installer member allowlist(exit 1) — reproduces production.genie-5.260901.2-linux-x64-glibc.tar.gzbuilt from this branch →"outcome":"committed", live bin holds all 8 members (exit 0).bun run check:fastgreen;bun test src/lib/install-promotion.test.ts scripts/install-swap.test.ts src/genie-commands/install-promote.test.ts src/genie-commands/__tests__/update-command-publication.test.ts scripts/release-docs.test.ts src/genie-commands/__tests__/update.test.ts→ 270 pass, 0 fail.Not in this PR (follow-ups)
release-update-path-smokeinstalls N and T bycp, never through a promoter. It needs to run N's promoter against T's payload (lease handshake + execution adapters).install.shreinstall; there is no way to fix an already-deployed binary from the tarball side.🤖 Generated with Claude Code
https://claude.ai/code/session_01FVnr6rZxYhbC8rU62A1U2i